Процедуры и файлы данных

Имена файлов

        Имена файлов есть последовательности различных символов, записываемых в одной из трех возможных форм: в двойных кавычках – строки, в одиночных наклонных кавычках и без кавычек – литералы или, по-другому, символы. Регистр символов в имени учитывается, знаки кириллицы использовать нельзя. Если в имени имеются специальные символы, например такие, как : (двоеточие), . (точка), пробел или \ (обратный слэш), то оно обязательно должно заключаться в двойные кавычки " или в одиночные наклонные кавычки `. Вот три записи одного и того же имени: myCriticalFile, "MyCriticalFile" и `MyCriticalFile`. В имени файла могут присутствовать один или несколько символов точки, например, "a.b.c.mw". Все части имени, находящиеся между двумя точками, и его часть, расположенная после последней точки, называются расширениями или уточнителями имени. Расширения обычно используются для указания типа файла, и их редко бывает больше одного. В Maple используются следующие стандартные расширения:

·       mw (mws до версии 9) – файлы документов (Worksheet Files);

·       mplфайлы Maple-языка (Maple Language Files);

·       mapletмаплет-файлы (Maplet Files);

·       m – файлы внутреннего формата (Internal Format Files);

·       mla, lib – библиотечные архивные файлы (Library Archives);

·       hdb – файлы базы данных помощи (Help Databases).

        Если требуется записать полное имя файла, то есть вместе с именем указать и путь доступа к файлу, то следует придерживаться следующих соглашений. Имя каталога отделяется от остальной части полного имени знаками :\\. Папки друг от друга и от имени файла отделяются знаками \\. Имя файла и его расширение разделяются точкой. Например, "E:\\Proba\\my\\boo.txt". Допускается и каноническая форма записи полного имени файла – "E:/Proba/ my/boo.txt"

        Имена файлов могут быть строковыми значениями (в кавычках) или литералами (без кавычек). В любом случае нельзя использовать кириллицу и длина имени не может превосходить 251. Имя-литерал строится из последовательности латинских букв, арабских цифр, символов списка {` , / , . , \ , ! , – , _ , : , $ , * , ~ , ?} и любых других знаков, заключенных в квадратные скобки, и отличных от символов пробела, табуляции и новой строки. Строковое имя может содержать любые символы, в том числе и пробелы.

        Примеры 1. Варианты открытия текстового или двоичного файла для чтения.

> 

restart:

{¿}

> 

# 1 вариант

{Shift+¿}

 

f := fopen("E:\\Proba\\Temp\\boo.txt", READ):

{¿}

> 

# 2 вариант

{Shift+¿}

 

f := fopen("E:/Proba/Temp/boo.txt", READ):

{¿}

> 

# 3 вариант

{Shift+¿}

 

f := fopen(`E:/Proba/Temp/boo.txt`, READ):

{¿}

> 

# 4 вариант

{Shift+¿}

 

tro := "E:/Proba/Temp/boo.txt":

{¿}

 

f := fopen(tro, READ):

Открытие файла для безбуферного чтения или записи

        Функция open(fi, mo) открывает файл с именем fi для безбуферной работы с ним в режиме чтения (mo = READ) или режиме записи (mo = WRITE) и возвращает дескриптор файла, являющийся  целым неотрицательным числом. Предварительное открытие файла для работы с ним не является обязательным. Первая же операция с неоткрытым файлом приводит к его автоматическому открытию. Безбуферное чтение или запись означает, что при работе с файлом дополнительная буферная память не используется. Специальные имена 'default' – ссылка на текущий поток данных, и 'terminal' – ссылка на поток данных верхнего уровня, с open(fi, mo)  не используются.

Открытие файла для буферного чтения или записи

        Функция fopen(fi, mo) открывает файл с именем fi для буферной работы с ним в режиме чтения (mo = READ), режиме записи (mo = WRITE) или режиме пополнения (mo = APPEND) и возвращает дескриптор файла, являющийся целым неотрицательным числом. Предварительное открытие файла для работы с ним не является обязательным. Первая же операция с неоткрытым файлом приводит к его автоматическому открытию. Буферное чтение или запись означает, что при работе с файлом используется дополнительная буферная память. Здесь могут использоваться специальные имена 'default' – ссылка на текущий поток данных, и 'terminal' – ссылка на поток данных верхнего уровня.

        Функция fopen(fi, mo, ty) выполняется так же, как и fopen(fi, mo), но здесь необязательным параметром ty Î {TEXT, BINARY} указывается тип файла fi. При ty = TEXT речь идет о текстовых файлах и о потоках символов. При ty = BINARY речь идет о двоичных файлах и о потоках байтов.

Закрытие файлов

        Функция close(fi1, fi2, …, fin) закрывает файлы с именами или дескрипторами fi1, fi2, …, fin, которые были открыты неявно или явно по open, fopen, pipe или popen. По A ничего не возвращается.

        Функция fclose(fi1, fi2, …, fin) выполняется идентично close(fi1, fi2, …, fin).

Текущая позиция в файле

        Функция filepos(fi) возвращает текущую позицию в файле с именем или дескриптором fi, то есть ту позицию в fi, начиная с которой будет считываться или записываться следующая порция данных. Позиция конца файла есть символ infinity.

        Функция filepos(fi, pos) устанавливает в качестве текущей позиции в файле fi значение pos. Это же значение и возвращается.

Конец файла

        Функция feof(fi) возвращает true тогда и только тогда, когда текущая позиция файла является позицией конца файла. В противном случае возвращается false.

Запись из документа в файл

        Функция save na1, na2, …, nak, fi  осуществляет запись переменных, процедур и модулей с именами na1, na2, …, nak в файл fi. Последний аргумент, то есть fi, вычисляется полностью, а остальные аргументы – только до имени. Если расширение fi есть m, то запись производится во внутреннем формате, иначе – в формате файлов Maple-языка.

Чтение из файла в документ

        Функция read fi осуществляет чтение в документ содержимого файла fi, ранее записанного по save. Обычно это файл в формате Maple-языка. Поэтому считанные переменные, процедуры и модули пригодны для проведения по ним вычислений или модификации. 

Удаление файлов

        Функция fremove(fi1, fi2, …, fin) удаляет файлы с именами или дескрипторами fi1, fi2, …, fin. Перед удалением открытые файлы закрываются. По fremove ничего не возвращается.

Запись в файл ввода в документ

        Команда writeto(fi)  переключает вывод результатов вычислений с терминала на вывод в новый или существующий текстовый файл с именем fi. Если файл с именем fi уже существует, то его прежнее содержимое не сохраняется. 

        Команда writeto(terminal) восстанавливает после writeto(fi)   стандартный режим вывода результатов вычислений на терминал.

        Команда appendto(fi) выполняется аналогично writeto(fi), но здесь запись ведется в существующий файл fi, причем все его данные сохраняется, а новые данные дополняют их.

Запись выражений в репозитарий

        Функция savelib(na1, na2, …, nak)  осуществляет запись выражений (переменных, процедур, модулей) с именами na1, na2, …, nak в Maple-репозитарий, то есть библиотечный файл.

Модули

        Функциональность системы символьных вычислений Maple существенно расширилась за счет введения понятия модуля, позволяющего использовать парадигму объектно-ориентированного программирования. Если процедура представляет собой объект, абстрагирующий программный код, который можно запускать на выполнение простым заданием имени процедуры и фактических значений ее аргументов, то модуль являются объектом, абстрагирующим данные и процедуры их обработки. Подобное объединение данных и процедур в единый модуль (оболочку, капсулу) называют инкапсуляцией. Данные модуля можно изменять только с помощью процедур модуля, экспортируемых в распоряжение пользователя и определяющих возможный интерфейс с ним.

Структура модуля

Структура модуля

        Модули в Maple – это выражения, создаваемые в результате вычисления синтаксическим анализатором специального определения или объявления модуля, которое в общем случае выглядит так:

mo := module()

#

mo – имя модуля;

 

description str;

#

str строки описание модуля;

 

export eseq;

#

eseqимена экспортируемых выражений;

 

local lseq;

#

lseqимена локальных выражений;

 

global gseq;

#

gseqимена глобальных выражений;

 

option opts;

#

optsпоследовательность опций;

body

#

bodyпоследовательность предложений;

end module

#

конечная строка модуля.

Рис. 1. Структура модуля

        На рисунке 1 после символов комментария # приведены краткие пояснения для отдельных разделов модуля. Разделы description, export, local, global, option задают описание модуля и его объектов. Раздел body называется телом модуля и представляет собой последовательность Maple-предложений, по которым реализуются вычисления. Любой из разделов не является обязательным. Раздел может занимать несколько строк документа, или, наоборот, несколько разделов размещаться в одной его строке. Разделы описания можно записывать в произвольном порядке, но все они должны предшествовать первому предложению тела body. Дадим более подробное описание элементов модуля:

·       module, description, export, local, global, option, end ключевые слова;

·       mo := module() – строка заголовка модуля;

·       end module (или end) – завершающая строка модуля;

·       description str – раздел (секция) описания модуля. Параметр str может быть задан литералом без пробелов, строкой или последовательностью строк. Описание служит комментарием для модуля и на его выполнение никакого влияния не оказывает;

·       export eseq – раздел объявления последовательности имен простых или типизированных (symbol::type) переменных, процедур и модулей. Пусть eseq = e1, e2, …, en.  Элементы ek (k = 1, 2, …, n) задаются именами соответствующих объектов и называются экспортируемыми членами или просто членами модуля. Они локальны внутри модуля, то есть это не глобальные имена, но доступны и вне модуля. Иными словами члены занимают как бы промежуточное положение между локальными и глобальными объектами. Доступ к членам модуля реализуется с помощью специального оператора :- выборки членов в синтаксисе mo:-ek, где mo – “внешнее” имя модуля (см. строку заголовка). Если модуль mo имеет в качестве члена подмодуль m с членом e, то доступ к е возможен по синтаксису mo:-m:-e;

·       local lseq – раздел объявления последовательности lseq имен локальных простых или типизированных переменных и процедур. Инициализация и определение этих объектов и (или) вычисления с их участием должны проходить в теле модуля. Вне модуля локальные объекты, вообще говоря, недоступны. Но можно создать определенные связи между экспортируемыми членами и локальными объектами так, что последние станут доступными и вне модуля;

·       global gseq – раздел объявления последовательности gseq имен глобальных переменных (но не процедур). Элементы gseq доступны как в модуле, так и вне его;

·       option optsнеобязательные объявления последовательности opts опций модуля. Вместо слова option можно писать options. Ключевые слова опций модуля, то есть левые части элементов opts могут быть такими: trace, copyright, load, unload, package и record. Смысл этих опций следующий:

o     copyright = “text” или `text`. Опция copyright значением text предоставляет общую информацию о модуле и уведомляет пользователя о правах разработчиков на него. Например, option `Copyright (C) Tula, TGPU Inc.2006`;

o     package. Наличие опции package сообщает системе, что модуль готов быть к размещению в Maple-архиве в виде пакета. Все члены такого модуля автоматически защищены;

o     load = lname. Пусть модуль загружен в Maple-архив и среди его локальных элементов или экспортных членов имеется объявление процедуры без аргументов с некоторым именем lname. Тогда при  наличии опция load = lname процедура lname выполняется при открытии модуля или при первом же обращении к любому его члену с помощью оператора выборки. Аналогичные действия реализуются процедурой с предопределенным именем ModuleLoad;

o     unload = uname. Пусть среди локальных элементов или экспортных членов модуля имеется объявление процедуры без аргументов с некоторым именем uname. Тогда при  наличии опция load = uname процедура uname выполняется перед сборкой мусора и при разрушении модуля (restart или выход из Maple). Аналогичные действия реализуются процедурой с предопределенным именем ModuleUnload;

o     trace. Наличие опции trace приводит к выводу дополнительной информации о модуле при его запуске;

o     record. Опция record объявляет модуль записью (см. конструктор Record();

·       body – последовательность из нуля или более Maple-предложений, составляющих тело модуля. Эти предложения используются для инициализации экспортируемых членов модуля и организации произвольных вычислений во время реализации модуля.

        Синтаксис модуля во многом напоминает синтаксис процедуры. И модули и процедуры могут содержаться друг в друге при любой глубине вложенности. Модули обладают свойствами и методами. Свойства модуля – это его локальные переменные, а методы – процедуры его интерфейса, то есть раздела export. Если заголовок модуля записан в форме mo := module name(), то name – это “внутреннее” имя модуля. Подобные именованные модули используются, в основном, системой. Модули, подобно любым другим выражениям, можно размещать в репозитарии, то есть в специальной библиотечной структуре для хранения между сессиями “возобновляемых” объектов (persistent). Заметим, что каждое вычисление модуля создает отдельный экземпляр модуля с собственным набором его локальных элементов и экспортируемых членов.

        Пример 2. В данном примере демонстрируется структура модуля со всеми его возможными разделами. Экспортируемые члены – процедуры plus7 и times7, а также переменная z. Дадим комментарий к приведенным по модулю oper вычислениям.

1.    oper:-plus7(1, 6) – вычисления по экспортируемой (интерфейсной) процедуре plus7 проведены успешно;

2.    oper:-times7(1, 6) – вычисления по экспортируемой процедуре times7 проведены успешно;

3.    oper:-lopro(1, 2) – вычисления по локальной процедуре lopro завершились сообщением “Error, module does not export `lopro`” (модуль не может экспортировать lopro);

4.    oper:-z – вычисления экспортируемой переменной z по локальной процедуре lopro проведены успешно;

5.    oper:-z := oper:-z+50 – вычисления выражения с экспортируемой переменной z проведены успешно;

6.    y^3+1 – вычисления с использованием глобальной переменной y проведены успешно.

> 

restart:

{Shift+¿}

> 

oper := module()

{Shift+¿}

 

   description "module structure";

{Shift+¿}

 

   export plus7, times7, z::typed;

{Shift+¿}

 

   local x, lopro;

{Shift+¿}

 

   global y;

{Shift+¿}

 

   option `Copyright (C) Tula, TGPU Inc.2006`;

{Shift+¿}

 

   #

{Shift+¿}

 

   x := 1: y := 2;

{Shift+¿}

 

   plus7 := (a, b) -> x+(a+b mod 7);

{Shift+¿}

 

   times7 := (a, b) -> y+(a*b mod 7);

{Shift+¿}

 

   lopro:= (a, b)-> x+y mod 7;

{Shift+¿}

 

   z := lopro(x, y);

{Shift+¿}

 

end module:

{¿}

 

 

 

> 

oper:-plus7(1, 6);  

{¿}

> 

oper:-times7(1, 6);

{¿}

> 

oper:-lopro(1, 2);  

{¿}

> 

oper:-z;

{¿}

> 

oper:-z := oper:-z+50;

{¿}

> 

y^3+1

{¿}

Процедуры инициализации и завершения работы с модулем

        Процедура ModuleLoad. Пусть модуль загружен в Maple-ар­хив и среди его локальных элементов или экспортных членов имеется объявление процедуры без аргументов с конкретным именем ModuleLoad.  Тогда  ModuleLoad выполняется при открытии модуля или при первом же обращении к любому его члену с помощью оператора выборки. Аналогичные действия, но с процедурой имеющей произвольное имя, организуются с помощью опции load.

        Процедура ModuleUnload. Пусть среди локальных элементов или экспортных членов модуля имеется объявление процедуры без аргументов с конкретным именем ModuleUnload. Тогда ModuleUnload выполняется перед сборкой мусора и при разрушении модуля (restart или выход из Maple). Аналогичные действия, но с процедурой имеющей произвольное имя, организуются с помощью опции unload.

10.2.  Разновидности модулей

Локальное связывание имен

        Команда use a in b end use. Команду with открытия пакетов нельзя применять внутри процедур и модулей. Работа в них со средствами различных пакетов расширений реализуется или записью длинных имен команд, или использованием локального связывания имен с конкретными значениями с помощью структуры use.  элемент a задает последовательность связываемых имен, действие которых распространяется на последовательность предложений b. Более ясное представление о связывании имен можно получить из рассмотрения примеров 2 и 3.   

        Пример 3. Составить процедуру, которая по строке возвращает список из количества латинских букв и количества цифр в ней.

        Решение. Процедура prouse решает поставленную задачу. В ней с помощью структуры use производится локальное связывание имен с пакетом StringTools. После этого между use и end use используются команды Length, IsAlpha и IsDigit этого пакета в короткой форме записи.

 

> 

prouse := proc(s::string)

{Shift+¿}

 

   local j, k, al, di;

{Shift+¿}

 

   al := 0; di := 0;

{Shift+¿}

 

   use StringTools in

{Shift+¿}

 

      k := Length(s):

{Shift+¿}

 

      for j from 1 to k do

{Shift+¿}

 

         if IsAlpha(s[j]) then al := al+1

{Shift+¿}

 

            elif IsDigit(s[j]) then di := di+1

{Shift+¿}

 

         end if

{Shift+¿}

 

      end do  

{Shift+¿}

 

   end use;

{Shift+¿}

 

   [al, di];

{Shift+¿}

 

end proc:

{¿}

 

 

 

 

prouse("asd4567re32");

{¿}

 

prouse("#67y$z");

{¿}

        Структуры use могут вкладываться друг в друга и используются не только для работы со средствами пакетов расширений, но и для связывания имен произвольных фрагментов программного кода. Ограничимся рассмотрением простейших примеров. 

        Примеры 3.

> 

mm := module() export c; c := 30; end module:

{Shift+¿}

 

use a = 2, b = 7, c = mm:-c in   # или просто mm:-c

{Shift+¿}

 

   a, b, c;

{Shift+¿}

 

   use b = 5, c = 3 in

{Shift+¿}

 

      a, b, c

{Shift+¿}

 

   end use;

{Shift+¿}

 

   a, b, c

{Shift+¿}

 

end use;

{¿}

> 

proc()

{Shift+¿}

 

   use a = 3+b, b = g(a) in

{Shift+¿}

 

      a + b

{Shift+¿}

 

   end use;

{Shift+¿}

 

end proc;

{¿}

 

proc() 3+b+g(a) end proc;

Модуль, запускаемый как процедура

        Процедура ModuleApply, объявленная среди экспортных членов некоторого модуля mo, позволяет запускать mo в синтаксисе mo(args), где args – последовательность аргументов ModuleApply. Фактически, mo(args) заменяет собой обращение mo:-ModuleApplay(args) к процедуре ModuleApply. Причем такое обращение возможно как из тела модуля, так и извне. 

 

        Пример 4. Здесь создан модуль mm, запускаемый как процедура. При обращении mm(k, a) генерируется квадратная матрица размером k´k, элементы которой псевдослучайные числа из диапазона 0..a (a ³ 0). При целом a элементы матрицы являются целыми неотрицательными числами. Кроме того, в модуле mm есть член eig, являющийся процедурой вычисления собственных значений матриц. Процедуры ModuleApply и eig используют средства пакета LinearAlgebra. Связывание имен реализуется структурой use.

 

> 

mm := module()

{Shift+¿}

 

   export ModuleApply, eig;

{Shift+¿}

 

   local a; 

{Shift+¿}

 

   use LinearAlgebra in

{Shift+¿}

 

      ModuleApply := proc(n::point, a::nonnegative)

{Shift+¿}

 

         RandomMatrix(n, generator = 0..a)

{Shift+¿}

 

      end proc:

{Shift+¿}

 

      eig := proc(ma) Eigenvalues(ma) end proc:

{Shift+¿}

 

   end use

{Shift+¿}

 

end module:

{¿}

 

 

 

> 

ma := mm(3, 10);

{¿}

> 

evalf(mm:-eig(ma));

{¿}

Ссылка на модуль из его тела

        Параметр thismodule позволяет реализовать ссылку на данный модуль из его тела. В некотором смысле это аналог ссылки procname в процедурах. Если модуль может запускаться как процедура, то ссылки на него изнутри реализуются разными способами, в том числе и обращением thismodule(args), где args – последовательность аргументов Modu­leApply.

        Пример 5.  Здесь на несколько видоизмененном модуле примера 4 демонстрируются различные варианты использования параметра thismodule. В процедуре eig по thismodule(a) формируется матрица ma размером 3´3 со случайным элементом a в первой строке и первом столбце. Фактически для формирования ma происходит обращение к процедуре ModuleApply. Затем вычисляются собственные значения ma. В процедуре info с помощью команды op, описываемой в следующем разделе, thismodule используется для вывода компонентов модуля.

> 

restart:

{Shift+¿}

 

mm := module()

{Shift+¿}

 

   export ModuleApply, eig, info;

{Shift+¿}

 

   local ma;

{Shift+¿}

 

   use LinearAlgebra in

{Shift+¿}

 

      ModuleApply := proc(a)

{Shift+¿}

 

          Matrix(3, 3, [[a, 0, 8], [10, 2, 1], [5, 6, 7]])

{Shift+¿}

 

      end proc:

{Shift+¿}

 

      eig := proc(a)

{Shift+¿}

 

         ma := thismodule(a): # или ma := mm(a):

{Shift+¿}

 

                                           # или ma := ModuleApply(a)

{Shift+¿}

 

         Eigenvalues(ma)

{Shift+¿}

 

      end proc:

{Shift+¿}

 

      info := proc(k) op(k, eval(thismodule)) end proc; 

{Shift+¿}

 

   end use

{Shift+¿}

 

end module:

{¿}

 

 

 

> 

mm(1), mm:-ModuleApply(1);

{¿}

> 

evalf(mm:-eig(1), 4);

{¿}

> 

mm:-info(1); mm:-info(2); mm:-info(3);

{¿}

Записи

        Конструктор Record(x, y, …) по слотам x, y, … (уникальным именам полей) создает объект, называемый записью. Фактически такие объекты являются модулями с опцией record и экспортируемыми членами, определяемыми слотами. Слоты могут быть именами или уравнениями. Правые части уравнений есть выражения или процедуры, а левые – их имена.

        Примеры 6.  В первом примере значения слотов записи формируется из документа. Во втором примере для первого слота значение сформировано в записи, а для третьего слота – из документа, но по процедуре, определенной в записи.

> 

Record(qw, ot, rs);

{¿}

 

module () export qw, ot, rs; option record; end module

 

> 

qw := 7: ot := "standart": rs := x^3+x: qw, ot, rs;

{¿}

> 

rr := Record(qw = 2, st, ot = proc(x::integer) 1+x^2 end proc);

{¿}

> 

rr:-st

{¿}

> 

rr:-qw := 5+t;

{¿}

> 

rr:-ot(5/7);

{¿}

> 

rr:-ot(5);

{¿}

        Команда verify(expr1, expr2, record). Две записи считаются равными, если они имеют одинаковые наборы слотов и значения в одноименных слотах равны. Запись, подобно массиву, имеет фиксированную длину, равную количеству слотов в ней, и, подобно таблице, адресует свои элементы именами. Команда возвращает true, если выражения expr1 и expr2 равны как записи, и false – в противном случае.

        Команда verify(expr1, expr2, record(ver)) возвращает true, если оба выражения expr1 и expr2 являются записями и равны по некоторому верификатору ver, то есть по специальному понятию равенства. 

 

Получение информации о модуле

Компоненты модуля

        Команда op(k, eval(mo)). Каждый модуль mo имеет три компонента (операнда), возвращаемых по команде при k = 1, 2 и 3. При k = 1  выводится последовательность экспортных членов модуля. При k = 2 выводится структура модуля, то есть все его разделы без кода (без тела). При k = 3 выводится последовательность локальных элементов модуля. Она может быть пустой.

        Команда op(eval(mo)) выводит последовательность из всех трех компонентов модуля mo.

        Команда eval(mo)выводит структуру модуля mo и равносильна  op(k, eval(mo)) при k = 2.

        Команда nops(eval(mo)) возвращает количество компонентов модуля mo, то есть число 3.

        Примеры 7. Здесь oper – модуль из примера 1.

 

> 

nops(eval(oper));

{¿}

> 

op(1, eval(oper));

{¿}

> 

op(2, eval(oper));

 

> 

op(3, eval(oper));

 

Экспорт имен членов модуля

        Команда exports(mo, opts) возвращает члены модуля mo, то есть последовательность имен его простых и типизированных переменных, процедур и модулей из раздела export. Необязательные опции opts могут быть следующими ключевыми словами:

·       instance (копия, экземпляр). По умолчанию возвращаются глобальные значения имен, то есть имя из модуля, а значение из рабочего пространства документа. Для того, чтобы возвращались точные экземпляры членов модуля (и имена, и значения), в exports(mo, opts) необходимо указать опцию instance;   

·       typed (типизированный). Если член объявлен с указанием типа, то по умолчанию возвращается только имя члена без части ::type. Для того, что члены возвращались полностью, в  exports(mo, opts) необходимо указать опцию typed.

        Примеры 8. Здесь oper – модуль из примера 1.

 

> 

z := 111: plus7 := 9:

{¿}

> 

g := exports(oper);

{¿}

> 

g[3], g[1](5, 6);

{¿}

> 

g := exports(oper, instance);

{¿}

> 

g[3], g[1](5, 6);

{¿}

> 

exports(oper, typed);

{¿}

> 

exports(oper, typed, instance);

{¿}

Тестирование на принадлежность объекту

        Команда member(el, mo, 'nu') тестирует выражение el на принадлежность к объекту mo, то есть к членам модуля или к элементам множества, списка или последовательности аргументов функции. Необязательный третий параметр nu является именем без значения. Если  он присутствует и по member(el, mo, 'nu') возвращается true, то nu для модуля становится равным первому аргументу el, а в остальных случаях – позиции первого вхождения el в mo.

        Примеры 9.

> 

m := module()

{Shift+¿}

 

   export e, f; local h;

{Shift+¿}

 

end module:

{¿}

> 

member(e, m), member(h, m)

{¿}

> 

member(f, m, 'num');

{¿}

> 

num

{¿}

> 

member(b, [a, b, c, d], 'n');

{¿}

> 

n;

{¿}

        Замечание. В принципе экспорт возможен не только из модуля. В примере 10 демонстрируется “экспорт” локальных элементов из процедуры.

        Пример 10. Перепишем модуль oper примера 1 в виде процедуры ope следующим образом:

 

> 

ope := proc(n::posint)

{Shift+¿}

 

   local plus, times, z::typed, x, lopro, y;

{Shift+¿}

 

   x := 1: y := 2;

{Shift+¿}

 

   plus := (a, b) -> x+(a+b mod n);

{Shift+¿}

 

   times := (a, b) -> y+(a*b mod n);

{Shift+¿}

 

   lopro:= (a, b)-> x+y mod n;

{Shift+¿}

 

   z := lopro(x, y);

{Shift+¿}

 

   plus, times, 'z', 'x', lopro, 'y'       # “export

{Shift+¿}

 

end proc:

{¿}

        При обращениях к процедуре ope возвращается последовательность plus, times, z, x, lopro, y. Как это можно использовать в вычислениях, показано ниже. Сравните получаемые значения с соответствующими результатами вычислений по модулю oper.

 

> 

z7:= ope(7);

{¿}

> 

z7[1](1, 6);

{¿}

> 

z7[2](1, 6);

{¿}

> 

z7[5](1, 2);

{¿}

> 

z7[3];

{¿}

> 

z7[3]+50;

{¿}

> 

z7[6]^3+1;

{¿}